﻿using System;
using System.Collections.Generic;
using System.Drawing;
using ProjectN.Core.Element;
using ProjectN.Core.Instance;

namespace ProjectN.Core.Fore
{
    public sealed class PageRenderer : IDisposable
    {
        // 这些都会在调用 Page.set 时设置，实际上构造函数运行后就不再是 null
        private IPage page = null!;
        private Bitmap img = null!;
        private Graphics gr = null!;
        private string status = null!;

        private Action<string> changeStatus;
        private Action requireRefresh;

        public PageRenderer(IPage page, Action<string>? onChangeStatus = null, Action? onRequireRefresh = null)
        {
            changeStatus = onChangeStatus ?? new Action<string>((status) => { });
            requireRefresh = onRequireRefresh ?? new Action(() => { });
            Page = page;
        }
        public IPage Page
        {
            get { return page; }
            set
            {
                page = value;

                img?.Dispose();
                gr?.Dispose();

                img = new Bitmap(PWidth, PHeight);
                gr = Graphics.FromImage(img);

                Update();
            }
        }
        public void Update()
        {
            Status = Properties.Resources.S_DRAWING;
            gr.Clear(BackgroundColor);
            requireRefresh();

            Queue<IElement> draw_queue = new Queue<IElement>();

            IElement current;
            foreach (IElement element in page.Elements)
            {
                if (element == null || element.Type.HasFlag(ElementType.Completion))
                    break;
                draw_queue.Enqueue(element);
                while (draw_queue.Count > 0)
                {
                    current = draw_queue.Dequeue();
                    if (current == null)
                        continue;
                    if (current.Type.HasFlag(ElementType.Basic))
                        current.OnDraw(gr);
                    if (current.Type.HasFlag(ElementType.Advanced))
                        foreach (IElement sub in current.Subelements)
                            draw_queue.Enqueue(sub);
                }
            }
            Status = Properties.Resources.S_READY;
            requireRefresh();
        }

        public string Status
        {
            get { return status; }
            set
            {
                status = value;
                changeStatus(value);
            }
        }
        public Image Image { get { return img; } }
        public int PWidth { get { return page.Width; } }
        public int PHeight { get { return page.Height; } }
        public string PIdentify { get { return page.Identity; } }
        public Color BackgroundColor { get { return page.BackgroundColor; } }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    gr.Dispose();
                    img.Dispose();
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。

                disposedValue = true;
            }
        }

        ~PageRenderer()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(false);
        }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
